/*
 * Copyright Hundsun Technologies Inc. All Rights Reserved.
 */

package checker

import (
	"context"

	"hundsun.com/hsl/hschain/consensus/types"

	"hundsun.com/hsl/hschain/consensus/common"

	"hundsun.com/hsl/hschain/common/config"
	"hundsun.com/hsl/hschain/common/log/logging"

	"github.com/golang/protobuf/proto"
	"hundsun.com/hsl/hschain/common/util/pb"
	"hundsun.com/hsl/hschain/module/common/utils"
	"hundsun.com/hsl/hschain/protos/consensus/raft"
)

var (
	// configParamBlockCheckInterval 校验区块间隔时间（单位:ms）
	configParamBlockCheckInterval = &utils.IntModuleConfigParam{Name: "blockCheckInterval", DefaultValue: 5}
	// configParamBlockFetchInterval 主动拉取区块间隔时间，即多久没收到区块则主动通知p2p去拉取（单位:ms）
	configParamBlockFetchInterval = &utils.IntModuleConfigParam{Name: "blockFetchInterval", DefaultValue: 3000}
	// configParamPendingBlockPoolFetchSize 从pendingBlockPool批量获取区块时单次请求能获取区块的数量
	configParamPendingBlockPoolFetchSize = &utils.IntModuleConfigParam{Name: "pendingBlockPoolFetchSize", DefaultValue: 10}
)

var defaultMiners []*raft.Miner

// NewChecker 新建一个checker模块
func NewChecker(client *common.BaseClient) *RaftChecker {
	b := &RaftChecker{
		baseclient: client,
	}
	return b
}

// RaftChecker raft checker
type RaftChecker struct {
	ctx        context.Context
	baseclient *common.BaseClient
	log        logging.Log
}

// Start 启动
func (m *RaftChecker) Start(rootCtx context.Context, cfg *config.ModuleConfig, log logging.Log) error {
	var err error
	genesisTxPayload := pb.GetGenesisTransactionPayload()
	consensusConfigPayloadBytes := genesisTxPayload.Consensus.Payload
	var consensusConfigPayload raft.ConsensusConfigPayload
	err = proto.Unmarshal(consensusConfigPayloadBytes, &consensusConfigPayload)
	if err != nil {
		panic(err)
	}
	defaultMiners = consensusConfigPayload.DefaultMiners
	if err != nil {
		return err
	}

	checkerConfig := &types.CheckerConfig{
		ModuleLog:                 log,
		BlockCheckInterval:        configParamBlockCheckInterval.GetValue(cfg, log),
		BlockFetchInterval:        configParamBlockFetchInterval.GetValue(cfg, log),
		PendingBlockPoolFetchSize: configParamPendingBlockPoolFetchSize.GetValue(cfg, log),
	}

	m.ctx = rootCtx

	err = m.baseclient.InitChecker(checkerConfig)
	if err != nil {
		return err
	}
	m.FetchAndCheckBlocks()
	return nil

}

// FetchAndCheckBlocks 拉取并验证区块
func (m *RaftChecker) FetchAndCheckBlocks() {
	startedSignal := make(chan struct{})
	checkerCtx, _ := context.WithCancel(m.ctx)
	go m.baseclient.Run(checkerCtx, startedSignal)
	<-startedSignal
}
